﻿using System;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime.Tracking;
using System.Reflection;

namespace Argos.Tracking
{
	/// <summary>
	/// Tracks execution of <see cref="StateActivity"/> activities in state machine workflows.
	/// </summary>
	public class StateTrackingService : PropertyTrackingServiceBase
	{

		/// <summary>
		/// Returns the name of the property holding the name of a state machine workflow's current state.
		/// </summary>
		public const string CurrentStateNamePropertyName = "CurrentStateName";

		///// <summary>
		///// Returns the name of the property holding the name of a state machine workflow's previous state.
		///// </summary>
		//public const string PreviousStateNamePropertyName = "PreviousStateName";



		#region public event EventHandler<ItemEventArgs<Guid>> CurrentStateChanged

		private EventHandler<ItemEventArgs<Guid>> CurrentStateChangedHandler;

		/// <summary>
		/// Fired when the current state of a workflow instance has changed.
		/// </summary>
		/// <remarks>
		/// The item of the event args contains the ID of the workflow instance
		/// whose current state has changed.
		/// </remarks>
		public event EventHandler<ItemEventArgs<Guid>> CurrentStateChanged
		{
			add { this.CurrentStateChangedHandler += value; }
			remove { this.CurrentStateChangedHandler -= value; }
		}

		#endregion



		#region public string GetCurrentStateName(Guid workflowInstanceId)

		/// <summary>
		/// Returns the name of the current state for the given workflow instance.
		/// </summary>
		/// <param name="workflowInstanceId">The ID of the workflow instance whose current state name to return.</param>
		public string GetCurrentStateName(Guid workflowInstanceId)
		{
			return this.GetWorkflowPropertyValue(workflowInstanceId, CurrentStateNamePropertyName) as string;
		}

		#endregion



		#region protected override bool IsPropertyTracked(PropertyInfo property)

		/// <summary>
		/// Filters out all other properties except the one containing the name of the current state.
		/// </summary>
		protected override bool IsPropertyTracked(PropertyInfo property)
		{
			return property.Name == CurrentStateNamePropertyName;
		}

		#endregion
		
		#region protected override bool IsWorkflowInstanceTracked(Guid instanceId, Type workflowType)

		/// <summary>
		/// Filters out workflow types other than those that extend the
		/// <see cref="StateMachineWorkflowActivity"/> type.
		/// </summary>
		protected override bool IsWorkflowInstanceTracked(Guid instanceId, Type workflowType)
		{
			return workflowType.IsStateMachineWorkflow();
		}

		#endregion
		
		#region protected virtual void OnCurrentStateChanged(ItemEventArgs<Guid> e)

		/// <summary>
		/// Fires the <see cref="StateChanged"/> event.
		/// </summary>
		/// <param name="e">The arguments for the event. The item contains the ID of the workflow instance whose current state has changed.</param>
		protected virtual void OnCurrentStateChanged(ItemEventArgs<Guid> e)
		{
			if (null != this.CurrentStateChangedHandler)
			{
				this.CurrentStateChangedHandler.Invoke(this, e);
			}
		}

		#endregion		
		
		#region protected override void OnWorkflowPropertyChanged(WorkflowPropertyChangedEventArgs e)

		/// <summary>
		/// Handles the property change and fires the <see cref="CurrentStateChanged"/> event.
		/// </summary>
		/// <param name="e">The arguments for the event.</param>
		protected override void OnWorkflowPropertyChanged(WorkflowPropertyChangedEventArgs e)
		{
			base.OnWorkflowPropertyChanged(e);

			if (e.PropertyName == CurrentStateNamePropertyName)
			{
				this.OnCurrentStateChanged(new ItemEventArgs<Guid>(e.InstanceId));
			}

		}

		#endregion

	}
}
